package com.gitee.wsl.compose.chart.xy.line.stack

import androidx.compose.animation.core.AnimationSpec
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Size
import com.gitee.wsl.common.ui.ext.path.lineTo
import com.gitee.wsl.common.ui.ext.path.moveTo
import com.gitee.wsl.compose.chart.KoalaPlotTheme
import com.gitee.wsl.compose.chart.SelectCheck
import com.gitee.wsl.compose.chart.xy.model.PointEntry
import com.gitee.wsl.compose.chart.xy.XYGraphScope
import com.gitee.wsl.compose.chart.xy.line.area.model.AreaBaseline
import com.gitee.wsl.compose.chart.xy.line.GeneralLinePlot
import com.gitee.wsl.compose.chart.xy.line.LineStackedPlot
import com.gitee.wsl.compose.chart.xy.line.LineStackedPlotSlate
import com.gitee.wsl.compose.chart.xy.model.ListPointEntry
import com.gitee.wsl.compose.chart.xy.model.ListPointSeriesAdapter


fun <X, Y> LineStackedPlot.StackedArea(
    styles: ( Int ) -> List<StackedAreaStyle>,
    firstBaseline: ( Int ) -> AreaBaseline.ConstantLine<X, Y>,
    animationSpec: @Composable ( Int ) -> AnimationSpec<Float> = { KoalaPlotTheme.animationSpec },
    selected:SelectCheck = { false }
):LineStackedPlotSlate<X, Y> = { index,data ->
    StackedAreaPlot(
        data = data,
        styles = styles(index),
        firstBaseline = firstBaseline(index),
        animationSpec = animationSpec(index),
        selected = selected(index)
    )
}


/**
 * A Stacked Area Plot is like a line plot but with filled areas between lines, and where each successive line
 * is added to all of the lines before it, so they stack.
 *
 * @param X Data type of x-axis values
 * @param Y Data type of y-axis values
 * @param data List of [MultiPoint] data items for the plot. Each MultiPoint must hold the same number of
 * y-axis values.
 * @param styles A list of [StackedAreaStyle]s to be applied to each series in the data. The size of this list must
 * match the number of data series provided by [data]
 * @param firstBaseline Provides the value for the bottom of the first line's area, in units of [Y]. Typically
 * this will be the 0 value for [Y]'s data type. Note: If the y-axis is logarithmic  this value cannot be 0.
 * @param animationSpec The animation to provide to the graph when it is created or changed.
 */
@Composable
fun <X, Y> XYGraphScope<X, Y>.StackedAreaPlot(
    data: List<ListPointEntry<X, Y>>,
    styles: List<StackedAreaStyle>,
    firstBaseline: AreaBaseline.ConstantLine<X, Y>,
    modifier: Modifier = Modifier,
    animationSpec: AnimationSpec<Float> = KoalaPlotTheme.animationSpec,
    selected:Boolean = false
) {
    if (data.isEmpty()) return

    GeneralLinePlot(
        ListPointSeriesAdapter(0,data),
        modifier,
        styles[0].lineStyle,
        null,
        styles[0].areaStyle,
        firstBaseline,
        animationSpec,
        selected
    ) { points: List<PointEntry<X, Y>>, size: Size ->
        moveTo(scale(points[0], size))
        for (index in 1..points.lastIndex) {
            lineTo(scale(points[index], size))
        }
    }

    for (series in 1..< data[0].y.size) {
        GeneralLinePlot(
            ListPointSeriesAdapter(series,data),
            modifier,
            styles[series].lineStyle,
            null,
            styles[series].areaStyle,
            AreaBaseline.ArbitraryLine(ListPointSeriesAdapter(series - 1,data)),
            animationSpec,
            selected
        ) { points: List<PointEntry<X, Y>>, size: Size ->
            moveTo(scale(points[0], size))
            for (index in 1..points.lastIndex) {
                lineTo(scale(points[index], size))
            }
        }
    }
}

